using lucere.analysis.index;
using lucere.analysis.score;

namespace lucere.service.search.collect
{
	///<summary>
	/// <p>Expert: Collectors are primarily meant to be used to
	/// gather raw results from a search, and implement sorting
	/// or custom result filtering, collation, etc. </p>
	///
	/// <p>Lucene's core collectors are derived from Collector.
	/// Likely your application can use one of these classes, or
	/// subclass <see cref="ITopDocsCollector"/>, instead of
	/// implementing Collector directly:
	///
	/// <ul>
	///      
	///   <li><see cref="ITopDocsCollector"/> is an abstract base class
	///   that assumes you will retrieve the top N docs,
	///   according to some criteria, after collection is
	///   done.  </li>
	///
	///   <li><see cref="ITopScoreDocCollector"/> is a concrete subclass
	///   <see cref="ITopDocsCollector"/> and sorts according to score +
	///   docID.  This is used internally by the <see cref="IIndexSearcher"/> 
	///   search methods that do not take an
	///   explicit <see cref="ISort"/>. It is likely the most frequently
	///   used collector.</li>
	///
	///   <li><see cref="ITopFieldCollector"/> subclasses <see cref="ITopDocsCollector"/>
	///   and sorts according to a specified
	///   <see cref="ISort"/> object (sort by field).  This is used
	///   internally by the <see cref="IIndexSearcher"/> search methods
	///   that take an explicit <see cref="ISort"/>.
	///   </li>
	///   <li><see cref="ITimeLimitingCollector"/>, which wraps any other
	///   Collector and aborts the search if it's taken too much
	///   time.</li>
	///
	///   <li><see cref="IPositiveScoresOnlyCollector"/> wraps any other
	///   Collector and prevents collection of hits whose score
	///   is &lt;= 0.0</li>
	///
	/// </ul>
	///
	/// <p>Collector decouples the score from the collected doc:
	/// the score computation is skipped entirely if it's not
	/// needed.  Collectors that do need the score should
	/// implement the <see cref="SetScorer"/> method, to hold onto the
	/// passed <see cref="IScorer"/> instance, and call <see cref="IScorer.Score()"/>
	///  within the collect method to compute the
	/// current hit's score.  If your collector may request the
	/// score for a single hit multiple times, you should use
	/// <see cref="ScoreCachingWrappingScorer"/>. </p>
	/// 
	/// <p><b>NOTE:</b> The doc that is passed to the collect
	/// method is relative to the current reader. If your
	/// collector needs to resolve this to the docID space of the
	/// Multi///Reader, you must re-base it by recording the
	/// docBase from the most recent setNextReader call.  Here's
	/// a simple example showing how to collect docIDs into a
	/// BitSet:</p>
	/// 
	/// <pre>
	/// Searcher searcher = new IndexSearcher(IIndexReader);
	/// final BitSet bits = new BitSet(IIndexReader.maxDoc());
	/// searcher.search(query, new Collector() {
	///   private int docBase;
	/// 
	///   <em>// ignore scorer</em>
	///   public void setScorer(Scorer scorer) {
	///   }
	///
	///   <em>// accept docs out of order (for a BitSet it doesn't matter)</em>
	///   public bool acceptsDocsOutOfOrder() {
	///     return true;
	///   }
	/// 
	///   public void collect(int doc) {
	///     bits.set(doc + docBase);
	///   }
	/// 
	///   public void setNextReader(IIndexReader reader, int docBase) {
	///     this.docBase = docBase;
	///   }
	/// });
	/// </pre>
	///
	/// <p>Not all collectors will need to rebase the docID.  For
	/// example, a collector that simply counts the total number
	/// of hits would skip it.</p></p>
	///</summary>
	public interface ICollector
	{
		///<summary>
		/// Called before successive calls to <see cref="Collect(int)"/>. Implementations
		/// that need the score of the current document (passed-in to
		/// <see cref="Collect(int)"/>), should save the passed-in Scorer and call
		/// scorer.score() when needed.
		///</summary>
		void SetScorer(IScorer scorer);

		///<summary>
		/// Called once for every document matching a query, with the unbased document
		/// number.
		/// Note: This is called in an inner search loop. For good search performance,
		/// implementations of this method should not call <see cref="ISearcher.Doc(int)"/> or
		/// <see cref="IIndexReader.Document(int)"/> on every hit.
		/// Doing so can slow searches by an order of magnitude or more.
		///</summary>
		void Collect(int doc);

		///<summary>
		/// Called before collecting from each IIndexReader. All doc ids in
		/// <see cref="Collect(int)"/> will correspond to reader.
		/// 
		/// Add docBase to the current IIndexReaders internal document id to re-base ids
		/// in <see cref="Collect(int)"/>.
		/// 
		/// @param reader
		///          next IIndexReader
		/// @param docBase
		///</summary>
		void SetNextReader(IIndexReader reader, int docBase);

		///<summary>
		/// Return <code>true</code> if this collector does not
		/// require the matching docIDs to be delivered in int sort
		/// order (smallest to largest) to <see cref="Collect"/>.
		///
		/// <p> Most Lucene Query implementations will visit
		/// matching docIDs in order.  However, some queries
		/// (currently limited to certain cases of <see cref="IBoolQuery"/>) can achieve faster searching if the
		/// <code>Collector</code> allows them to deliver the
		/// docIDs out of order.</p>
		///
		/// Many collectors don't mind getting docIDs out of
		/// order, so it's important to return <code>true</code>
		/// here.
		///</summary>
		bool AcceptsDocsOutOfOrder { get; }
	}
}